package com.otherTest.java8;

import org.junit.Test;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * java8 新增时间类测试
 * 原有java时间处理类存在的问题
 * <p>
 * 1-Java的日期/时间类的定义并不一致，在java.util和java.sql的包中都有日期类，此外用于格式化和解析的类在java.text包中定义。
 * 2-java.util.Date同时包含日期和时间，而java.sql.Date仅包含日期，将其纳入java.sql包并不合理。另外这两个类都有相同的名字，这本身就是一个非常糟糕的设计。
 * 3-对于时间、时间戳、格式化以及解析，并没有一些明确定义的类。对于格式化和解析的需求，我们有java.text.DateFormat抽象类，但通常情况下，SimpleDateFormat类被用于此类需求。
 * 4-所有的日期类都是可变的，因此他们都不是线程安全的，这是Java日期类最大的问题之一。
 * 5-日期类并不提供国际化，没有时区支持，因此Java引入了java.util.Calendar和java.util.TimeZone类，但他们同样存在上述所有的问题
 *
 * @author Conceit
 * 2018/2/1 增加方法
 * @since 1.0.0, 2018/2/1
 */
public class TestJava8Date {

    /**
     * java.time包
     * <p>
     * 这是新的Java日期/时间API的基础包，所有的主要基础类都是这个包的一部分
     * 如：LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration等等。
     * 所有这些类都是不可变的和线程安全的，在绝大多数情况下，这些类能够有效地处理一些公共的需求。
     */
    @Test
    public void testJava8JavaTimePackage() {
//LocalDate类是一个不可变的类，它表示默认格式(yyyy-MM-dd)的日期/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        //可以使用now()方法得到当前时间
        //2018-02-06
        LocalDate todayLocalDate = LocalDate.now();
        System.out.println(todayLocalDate);

        //也可以提供输入年份、月份和日期的输入参数来创建一个LocalDate实例
        //2018-07-01
        LocalDate firstDay2018LocalDate = LocalDate.of(2018, Month.JULY, 1);
        System.out.println(firstDay2018LocalDate);

        //传入ZoneId来获得指定时区的日期
        //2018-02-06
        LocalDate asiaShanghaiLocalDate = LocalDate.now(ZoneId.of("Asia/Shanghai"));
        System.out.println(asiaShanghaiLocalDate);

        //加上1970-01-01的天数,
        //1970-01-11
        LocalDate dateFromBaseLocalDate = LocalDate.ofEpochDay(10);
        System.out.println(dateFromBaseLocalDate);

        //计算2014年的第100天 100th day of 2014
        //2014-04-10
        LocalDate hundredDay2014LocalDate = LocalDate.ofYearDay(2014, 100);
        System.out.println(hundredDay2014LocalDate);
//LocalTime类是一个不可变的类，它的实例代表一个符合人类可读格式的时间，默认格式是hh:mm:ss.zzz/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        //获取当前时间 默认格式是hh:mm:ss.zzz
        //16:03:00.317
        LocalTime nowLocalTime = LocalTime.now();
        System.out.println(nowLocalTime);

        //同时也可以传入小时、分钟和秒,纳秒输入参数创建实例
        //12:20:25.000000040
        LocalTime custerLocalTime = LocalTime.of(12, 20, 25, 40);
        System.out.println(custerLocalTime);

        //获取指定时区的时间
        //16:21:39.172
        LocalTime shanghaiLocalTime = LocalTime.now(ZoneId.of("Asia/Shanghai"));
        System.out.println(shanghaiLocalTime);

        //计算1970年一月一日加上传入的秒数 得到的时间
        //00:00:01
        LocalTime ofSecondOfDaylocalTime = LocalTime.ofSecondOfDay(100);
        System.out.println(ofSecondOfDaylocalTime);

//LocalDateTime是一个不可变的日期-时间对象，它表示一组日期-时间，默认格式是yyyy-MM-dd-HH-mm-ss.zzz。它提供了一个工厂方法，接收LocalDate和LocalTime输入参数/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        //获取当前经过默认格式化的时间格式
        //2018-02-07T10:06:57.235
        LocalDateTime nowLocalDateTime = LocalDateTime.now();
        System.out.println(nowLocalDateTime);

        //使用自定义传入的LocalDate和LocalTime 获取时间
        //2018-02-07T10:06:57.235
        LocalDateTime clusterTodayLocalDateTime = LocalDateTime.of(LocalDate.now(), LocalTime.now());
        System.out.println(clusterTodayLocalDateTime);

        //使用自定义传入的年月日小时分钟秒，获取默认格式的时间
        //2014-01-01T10:10:30
        LocalDateTime clusterLocalDateTime = LocalDateTime.of(2014, Month.JANUARY, 1, 10, 10, 30);
        System.out.println(clusterLocalDateTime);

        //获取指定时区的时间
        //2018-02-07T11:53:03.788
        LocalDateTime AsiaTokyoLocalDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
        System.out.println(AsiaTokyoLocalDateTime);

        //获取使用秒的实例1970-01-01t00:00:00z
        //1970-01-01T00:00
        LocalDateTime dateFromBaseLocalDateTime = LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC);
        System.out.println("0th second time from 01/01/1970= " + dateFromBaseLocalDateTime);

// java.time.Instant：Instant类是用在机器可读的时间格式上的，它以Unix时间戳的形式存储日期时间/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        //获取unix当前时间戳
        //2018-02-07T03:13:23.924Z
        Instant nowInstant = Instant.now();
        System.out.println(nowInstant);

        //获取当前时间的毫秒数
        //1517974150499
        Long nowEpochMilliInstant = Instant.now().toEpochMilli();
        System.out.println(nowEpochMilliInstant);

        //当前时间的毫秒数转换为Instant
        //2018-02-07T03:32:26.499Z
        Instant specificTime = Instant.ofEpochMilli(nowEpochMilliInstant);
        System.out.println("Specific Time = " + specificTime);

        //计算两个“时间”的间隔Duration--DateTime
        Duration between = Duration.between(clusterLocalDateTime, AsiaTokyoLocalDateTime);
        System.out.println(between);
        //可以转换为毫秒值
        System.out.println(between.toMillis());

        //计算两个“日期”间隔Period --date
        LocalDate s = LocalDate.of(2018, 8, 24);

        LocalDate now = LocalDate.now();

        Period be = Period.between(s, now);

        //得到这一时期的年表，也就是ISO日历系统
        System.out.println(be.getChronology());
        //[Years, Months, Days]
        System.out.println(be.getUnits());

        System.out.println(be.getYears());//间隔了多少年

        System.out.println(be.getMonths());//间隔了多少月

        System.out.println(be.getDays());//间隔多少天

        //以上方法是按照年月日总体算的

        //这个方法才是正宗计算两个LocalData 日期相差天数的王道
        System.out.println(s.toEpochDay() - now.toEpochDay());
    }


    /**
     * 一些常用的日期计算api
     * <p>
     * 如：加/减天数、周数、月份数，等等
     */
    @Test
    public void testJava8TimeCalculateApi() {
        LocalDate nowLocalDate = LocalDate.now();
        //得到年份
        //2018
        nowLocalDate.getYear();
        System.out.println(nowLocalDate.getYear());
        //检查是否是闰年
        //false
        nowLocalDate.isLeapYear();
        System.out.println(nowLocalDate.isLeapYear());

        LocalDate plusLocalDate = LocalDate.now();
        //加年 月 周 日
        //2018-02-08
        System.out.println(nowLocalDate.plusDays(1));
        //2018-03-07
        System.out.println(plusLocalDate.plusMonths(1));
        //2018-02-14
        System.out.println(plusLocalDate.plusWeeks(1));
        //2019-02-07
        System.out.println(plusLocalDate.plusYears(1));

        LocalDate minusLocalDate = LocalDate.now();
        //减年 月 周 日
        //2018-02-06
        System.out.println(nowLocalDate.minusDays(1));
        //2018-01-07
        System.out.println(plusLocalDate.minusMonths(1));
        //2018-01-31
        System.out.println(plusLocalDate.minusWeeks(1));
        //2017-02-07
        System.out.println(plusLocalDate.minusYears(1));

        LocalDateTime localDateTime = LocalDateTime.now();
        //求当前月的第一天
        //2018-02-01T15:37:39.118
        System.out.println("First date of this month= " + localDateTime.with(TemporalAdjusters.firstDayOfMonth()));
        //求当前年的最后一天 也可以直接用LocalDate
        //2018-12-31T15:37:39.118
        System.out.println(localDateTime.with(TemporalAdjusters.lastDayOfYear()));

        //求指定时间是礼拜几


        //
        LocalDate periodLocalDate = LocalDate.now();
        periodLocalDate = periodLocalDate.with(TemporalAdjusters.lastDayOfYear());
        Period period = nowLocalDate.until(periodLocalDate);
        System.out.println("Period Format= " + period);
        System.out.println("Months remaining in the year= " + period.getMonths());

    }


    /**
     * 解析和格式化工具类
     * <p>
     * 解析和格式化：将一个日期格式转换为不同的格式，之后再解析一个字符串，得到日期时间对象
     * 常用方法
     */
    @Test
    public void testJava8TParseFormatApi() {

        LocalDate nowLocalDate = LocalDate.now();
        //按照指定的格式格式输出nowLocalDate
        System.out.println(nowLocalDate.format(DateTimeFormatter.BASIC_ISO_DATE));

        LocalDateTime nowLocalDateTime = LocalDateTime.now();
        //按照指定的格式格式输出nowLocalDateTime
        System.out.println(nowLocalDateTime.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss")));

        //将已经格式化的String时间，按照指定的时间格式为LocalDateTime
        //2018-02-09T10:57:29.516
        LocalDateTime parseNowLocalDateTime = LocalDateTime.now();
        System.out.println(parseNowLocalDateTime.parse("2018年09月30日 10:56:05", DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss")));

        //获取当前时间0点时间,结束时间
        LocalDateTime newDateTime = LocalDateTime.ofEpochSecond(Long.valueOf(new Date().toInstant().toEpochMilli()) / 1000, 0, ZoneOffset.UTC);
        LocalDateTime startTime = newDateTime.withHour(0).withMinute(0).withSecond(0).withNano(0);
        LocalDateTime endTime = newDateTime.withHour(23).withMinute(59).withSecond(59).withNano(999999999);

        //计算两个“日期”间隔Period --date
        LocalDate s = LocalDate.of(2018, 10, 11);
        LocalDate now = LocalDate.now();
        System.out.println(startTime.toLocalDate().toEpochDay() - endTime.toLocalDate().toEpochDay());

        //时间加减
        System.out.println(LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault()).plusDays(1));

    }

    /**
     * 旧的日期时间支持
     * <p>
     * <p>
     * 常用方法
     */
    @Test
    public void testJava8Compatibility() {

        //指定unix时间戳和时区key 转换为localDateTime,此处获取东京时区
        //2018-02-09T16:31:23.892
        Instant timestamp = new Date().toInstant();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(timestamp, ZoneId.of(ZoneId.SHORT_IDS.get("JST")));
        System.out.println(localDateTime);

        //Calendar to Instant
        Instant time = Calendar.getInstance().toInstant();
        System.out.println(time);

        //TimeZone to ZoneId
        //获取当前时区
        //Asia/Shanghai
        ZoneId defaultZone = TimeZone.getDefault().toZoneId();
        System.out.println(defaultZone);

        //Date API to Legacy classes
        //Date to localDataTime
        Date date = Date.from(Instant.now());
        System.out.println(date);

        TimeZone tz = TimeZone.getTimeZone(defaultZone);
        System.out.println(tz);

        //date 和 localdatatime 互相转换
        Date nowDate = new Date();
        LocalDateTime converLocalDateTime = LocalDateTime.ofInstant(nowDate.toInstant(), ZoneId.systemDefault());

        LocalDateTime nowlocalDateTime = LocalDateTime.now();
        Date converDate = Date.from(nowlocalDateTime.atZone(ZoneId.systemDefault()).toInstant());



    }

    @Test
    public void test(){
        String roundDayStart=new String("08:00");
        String roundDayStarts[]=roundDayStart.split(":");
        Integer roundDayStartHour=Integer.parseInt(roundDayStarts[0]);
        Integer roundDayStartMinute=Integer.parseInt(roundDayStarts[1]);
        System.out.println(roundDayStartHour);
        System.out.println(roundDayStartMinute);

//        LocalDateTime localDateTimeStart=LocalDateTime.parse("08:00", DateTimeFormatter.ofPattern("HH:mm"));
//        System.out.println(localDateTimeStart);

        LocalDateTime current=LocalDateTime.now();
        System.out.println(current);
        LocalDateTime localDateTimeStartCopy = LocalDateTime.of(current.getYear(), current.getMonth(), current.getDayOfMonth(),roundDayStartHour , roundDayStartMinute);
        System.out.println(localDateTimeStartCopy);

        System.out.println(current.isBefore(localDateTimeStartCopy));
        System.out.println(current.isAfter(localDateTimeStartCopy));


    }

    @Test
    public void test2(){
        LocalDateTime localDateTime=LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());
        System.out.println(localDateTime.getDayOfMonth());

    }

    @Test
    public void test3(){
        LocalDateTime localDateTime=LocalDateTime.now();
        System.out.println(localDateTime.getMonth().maxLength());
       // System.out.println(localDateTime.withMonth());

    }

	@Test
	public void test4(){
		LocalDateTime localDateTime=LocalDateTime.now();
		System.out.println(localDateTime.withDayOfMonth(1));
		System.out.println(localDateTime.getMonth().getValue());
	}

	@Test
	public void test5(){
        Date currentDate=new Date();
        //上个月的当前时间
        Date lastMonth=DateTimeUtil.minusMonth(currentDate,1);
        //上个月的共有几天
        int countDayInLastMonth=DateTimeUtil.countDayInMonth(lastMonth);

        //上个月时间格式化
        String str=DateTimeUtil.format(lastMonth,DateTimeUtil.FormatEnum.yyyyMM.value);


        System.out.println(str);


    }
}
